#ifndef _UTILS_H
#define _UTILS_H

#include "DDAP.pb.h"
#include "UAV-IDAuth.pb.h"
#include "globalDefine.h"

#include <chrono>
#include <cstddef>
#include <cstdint>
#include <cstring>
#include <iostream>
#include <mqueue.h>
#include <netdb.h>
#include <netinet/in.h>
#include <openssl/err.h>
#include <openssl/md5.h>
#include <openssl/ssl.h>
#include <openssl/types.h>
#include <queue>
#include <string>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <vector>
#define BUFFER_SIZE 4096
namespace droneswarm
{
    typedef std::chrono::steady_clock::time_point TimePoint;

    // 和message绑定的
    struct messageInfo
    {
        messageInfo()
            : messageID( "" )
            , sourceAddress( 0 )
            , destinationAddress( 0 )
            , realData( "" )
            , realDataLength( 0 )
            , mt( AUTH_REQUEST )
            , version( "V1" )
            , needAck( false )
            , fragment( false )
            , is_Encry( false )
            , cpt( COMP_NONE )
            , enct( ENC_NONE )
            , dataType( NOTBOTH )
        {
        }

        std::string messageID;
        uint32_t sourceAddress;
        uint32_t destinationAddress;
        std::string realData;
        uint32_t realDataLength;
        MessageType mt;       // 消息类型
        std::string version;  // 报文格式的版本
        bool needAck;         // 是否需要确认报文
        bool fragment;
        bool is_Encry;
        CompressionType cpt;
        EncryptionType enct;
        DataType dataType;
    };

    struct DroneData
    {
        std::string id;
        std::string deviceType;
        std::string model;
        std::string status;
    };

    // 这是定义消息队列的消息类型的枚举
    enum DataOperator
    {
        DATAUPLOAD = 1,
        DATADOWNLOAD,
        DATAUPLOADRESPONSE,
        DATADOWNLOADRESPONSE,
        DATAUPDATE,
        DATAUPDATERESPONSE
    };

    enum udpMessage
    {
        BROADCAST_MESSAGE = 0,
        MULTICAST_MESSAGE = 1,
        UNICAST_MESSAGE = 2,
    };

    // struct clusterHead
    // {
    //     std::string ipAddrerss;
    //     EVP_PKEY *masterPubkey;
    //     double signalStrength;   // 这是信号强度
    //     double distance;         // 这是距离
    //     double remainingEnergy;  // 这是剩余能量
    //     double load;             // 这是负载
    // };

    // size_t是无符号整数类型，大小取决于平台的位数。
    // 消息队列的消息格式
    // 数据的格式是[id,deviceType,model,status],[id,deviceType,model,status]
    typedef struct BlockChainOperatorMsg
    {
        int fd;  // 这是用来标记消息属于谁的
        DataOperator daop;
        char data[ 4096 ];  // 消息缓冲区
        size_t data_len;    // 消息缓冲区中实际数据的个数

    public:
        void clearBlockData()
        {
            memset( data, 0, sizeof( data ) );
            data_len = 0;
        }

    } BlockOpMsg;

    struct commMessage
    {
        struct sockaddr_in sendAddress;
        size_t address_len;
        enum udpMessage um;
        std::string data;  // 这是数据
        commMessage()
        {
            memset( &sendAddress, 0, sizeof( sendAddress ) );
            address_len = sizeof( sendAddress );
        }
    };

    const int MAX_BUFF = 4096;
    // 断言处理
    void CondPanic( bool condition, std::string err );
    ssize_t readn( int fd, void *buff, size_t n );
    ssize_t readn( int fd, std::string &inBuffer, bool &zero );
    ssize_t readn( int fd, std::string &inBuffer );

    ssize_t writen( int fd, void *buff, size_t n );
    ssize_t writen( int fd, std::string &sbuff );
    void shutDownWR( int fd );

    // 在这里写一个读取文件的方法,返回值为string类型
    std::string readFromFile( std::string path );

    std::string DateFormat();
    std::string modifyFilePath( const std::string &fileName );
    int socket_bind_listen( int port );
    void handle_for_sigpipe();
    int setSocketNonBlocking( int fd );
    void setSocketNodelay( int fd );
    // SSL_CTX *initializeSSL();
    uint64_t getTime();
    // 这个函数是根据数据 使用SHA256()哈希函数来生成哈希值，主要用于将生成的哈希值与消息头字段的checkNum
    std::string sha256_check( const unsigned char *data, size_t length );
    // 下面重载函数，一个用于处理FullMessage 一个用于处理SigningMessage
    bool readAndDeserialize( FullMessage &message,
                             int fd,
                             char *receiveBuff,
                             char *tmpBuffer,
                             size_t receiveBuff_length,
                             size_t tmpBuffer_length,
                             int timeout );
    bool readAndDeserialize( SigningMessage &signMessage,
                             int fd,
                             char *receiveBuff,
                             char *tmpBuffer,
                             size_t receiveBuff_length,
                             size_t tmpBuffer_length,
                             int timeout );
    bool readAndDeserialize( needHMACMessage &hmacMessage,
                             int fd,
                             char *receiveBuff,
                             char *tmpBuffer,
                             size_t receiveBuff_length,
                             size_t tmpBuffer_length,
                             int timeout );
    bool parseMessage( FullMessage &message,
                       int accept_fd,
                       MessageType &mt,
                       std::string &version,
                       uint32_t &sourceAddress,
                       uint32_t &destinationAddress,
                       std::string &messageID,
                       bool &needAck,
                       bool &fragment,
                       bool &is_Encry,
                       CompressionType &cpt,
                       EncryptionType &enct,
                       char *data_c,
                       size_t &dataSize );
    bool parseMessage( FullMessage &message, messageInfo &minfo, int fd );
    std::string constructMessage( std::string sourceData,
                                  uint32_t sourceDataLength,
                                  MessageType mt,
                                  std::string version,
                                  uint32_t sourceAddress,
                                  uint32_t destinationAddress,
                                  bool needAck,
                                  bool fragmet,
                                  bool is_Encry,
                                  CompressionType cpt,
                                  EncryptionType enct );
    std::string constructMessage( FullMessage &message, messageInfo &messInfo );
    std::vector< std::string > getLocalIPv4Addresses();
    uint32_t ipv4StringToUint32( const std::string &ipv4Str );
    std::string uint32ToIpv4String( uint32_t ipv4Uint32 );
    // 这是用于按照规则来设置MessageInfo的函数
    void setMessageInfo( struct messageInfo &mi, MessageType mt );
    void setDataTypeMessageInfo( struct messageInfo &mi, DataType dataType );
    bool generateHmac( const unsigned char *data,
                       size_t data_len,
                       const unsigned char *key,
                       size_t key_len,
                       unsigned char **hmac_value,
                       size_t *outlen );
    bool verifyHmac( unsigned char *computeHmac, unsigned char *receiveHmac, size_t hmacLen );
    std::vector< DroneData > parseReceiveDroneData( std::string data );  // 这是分析接收的无人机数据
    void extractDroneData( std::vector< DroneData > &drones, std::string &data );

    ssize_t myMqTimeRead( mqd_t mq, char *data, size_t dataLen, int maxTries );
    ssize_t myMqTimeSend( mqd_t mq, char *data, size_t dataLen, int maxTries );

    /*
    "0x12345678","0x12345676","0x12345676","0x12345676","0x12345675"
    "DJI","DJI","DJI","DJI","DJI"
    "master","master","master","master","master"
    "legitimate","legitimate","legitimate","legitimate","legitimate"
    这个函数的作用是将先前已经提取出来的上述字符串，分别填入到DroneData结构的Vector的容器中。
    */

    void partially_Extract_WhiteOrBlack_DroneData( std::vector< DroneData > &drones, const std::string data, int i );

    /*

    [["0x12345678","0x12345676","0x12345676","0x12345676","0x12345675"],["DJI","DJI","DJI","DJI","DJI"],["master","master","master","master","master"],["legitimate","legitimate","legitimate","legitimate","legitimate"]]

    这个函数是用来处理上述的区块链返回过来的单一的无人机信息，如非法或者合法。
    我们需要将其提取出来，并填入到相应个数的std::vector< DroneData > 容器中。
    */
    std::vector< DroneData > completeExtract( std::string data );

    // 这个函数是处理非法和合法数据在一起发送过来的。我们blockChainInterface接口中，我们定义了这两个字符串之间使用\n来换行
    // 因此我们通过\n来划分数据
    void divideBothDroneData( std::string rawData, std::string *illegalString, std::string *legitimateString );

    // 检查目录是否存在，如果不存在则创建它
    bool createDirectory( const std::string &path );

    // 递归创建多级目录
    bool createDirectories( const std::string &path );
    std::string getLocalIPAddress();
    ssize_t receiveUdp( int fd, std::string &inBuffer, struct sockaddr_in *sender_address, socklen_t *arrLen );
    ssize_t sendtoUdp( int fd, std::string &outBuffer, struct sockaddr_in *dest_address, socklen_t dest_arrLen );
    bool readPubKeyCertificate( const std::string &path, std::string &cerStr );
    ssize_t receiveUdpMore( int fd,
                            std::queue< std::string > &inBufferQueue,
                            struct sockaddr_in *sender_address,
                            socklen_t &arrLen,
                            std::mutex &mutex,
                            enum udpMessage *um );
    ssize_t receiveUdpData( int fd, struct commMessage *messageInfo );
    ssize_t sendUdpMore( int fd,
                         std::string &content,
                         struct sockaddr_in destination_address,
                         socklen_t &arrLen,
                         std::string destination_address_str );
    BIGNUM *generate_large_serial_number();
    bool generateHmacKey( unsigned char *AesKey, std::string token );
    int compareASN1Time( const ASN1_TIME *time1, const ASN1_TIME *time2 );
    bool Extract_and_verify_cert_is_valid( X509 **pubCert, const std::string &certificatePath );
    bool check_certificate_content_validity_period( X509 *pubCert );
    void print_openssl_error();
    int getRandomPort();
    char *encode_csr_to_pem( X509_REQ *req );
    X509_REQ *decode_csr_from_pem( const char *pem_c );
    char *encode_Cert_to_pem( X509 *cert );
    X509 *decode_Cert_from_pem( const char *pem_c );
    std::string EVP_PKEYToString( EVP_PKEY *pkey );
    EVP_PKEY *stringToEVP_PKEY( const std::string &pubKeyStr );
    bool checkTimestamp_Num( const std::string &timeStamp, const std::string checkNum, const std::string &data );
    std::string getIpString( struct sockaddr_in sendAddress );
}  // namespace droneswarm

#endif